﻿#include "ZumaMonster.h"
#include "../../MirEnvir/Envir.h"
#include "../../../Shared/ServerPackets.h"
#include "../../MirEnvir/Map.h"
#include "../../../Shared/Functions/Functions.h"
#include "../SpellObject.h"

using namespace Server::MirDatabase;
using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    bool ZumaMonster::getCanMove() const
    {
        return MonsterObject::getCanMove() && !Stoned;
    }

    bool ZumaMonster::getCanAttack() const
    {
        return MonsterObject::getCanAttack() && !Stoned;
    }

    ZumaMonster::ZumaMonster(MonsterInfo *info) : MonsterObject(info)
    {
    }

    int ZumaMonster::Pushed(MapObject *pusher, MirDirection dir, int distance)
    {
        return Stoned ? 0 : MonsterObject::Pushed(pusher, dir, distance);
    }

    void ZumaMonster::ApplyPoison(Poison *p, MapObject *Caster, bool NoResist, bool ignoreDefence)
    {
        if (Stoned)
        {
            return;
        }

        MonsterObject::ApplyPoison(p, Caster, NoResist, ignoreDefence);
    }

    Server::MirObjects::Buff *ZumaMonster::AddBuff(BuffType type, MapObject *owner, int duration, Stats *stats, bool visible, bool infinite, bool stackable, bool refreshStats, std::vector<int> &values)
    {
        if (Stoned)
        {
            return nullptr;
        }

        return MonsterObject::AddBuff(type, owner, duration, Stats, visible, infinite, stackable, refreshStats, {values});
    }

    bool ZumaMonster::IsFriendlyTarget(PlayerObject *ally)
    {
        if (Stoned)
        {
            return false;
        }

        return MonsterObject::IsFriendlyTarget(ally);
    }

    void ZumaMonster::ProcessAI()
    {
        if (!Dead && getEnvir()->getTime() > ActionTime)
        {
            bool stoned = !FindNearby(2);

            if (Stoned && !stoned)
            {
                Wake();
                WakeAll(14);
            }
        }

        MonsterObject::ProcessAI();
    }

    void ZumaMonster::Wake()
    {
        if (!Stoned)
        {
            return;
        }

        Stoned = false;
        S::ObjectShow *tempVar = new S::ObjectShow();
        tempVar->ObjectID = ObjectID;
        Broadcast(tempVar);
        ActionTime = getEnvir()->getTime() + 1000;

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    void ZumaMonster::WakeAll(int dist)
    {

        for (int y = getCurrentLocation()->Y - dist; y <= getCurrentLocation()->Y + dist; y++)
        {
            if (y < 0)
            {
                continue;
            }
            if (y >= getCurrentMap()->Height)
            {
                break;
            }

            for (int x = getCurrentLocation()->X - dist; x <= getCurrentLocation()->X + dist; x++)
            {
                if (x < 0)
                {
                    continue;
                }
                if (x >= getCurrentMap()->Width)
                {
                    break;
                }

                Cell *cell = getCurrentMap()->GetCell(x, y);

                if (!cell->getValid() || cell->Objects.empty())
                {
                    continue;
                }

                for (int i = 0; i < cell->Objects.size(); i++)
                {
                    ZumaMonster *target = dynamic_cast<ZumaMonster*>(cell->Objects[i]);
                    if (target == nullptr || !target->Stoned)
                    {
                        continue;
                    }
                    target->Wake();
                    target->setTarget(getTarget());
                }
            }
        }

    }

    bool ZumaMonster::IsAttackTarget(MonsterObject *attacker)
    {
        return !Stoned && MonsterObject::IsAttackTarget(attacker);
    }

    bool ZumaMonster::IsAttackTarget(PlayerObject *attacker)
    {
        return !Stoned && MonsterObject::IsAttackTarget(attacker);
    }

    bool ZumaMonster::Walk(MirDirection dir)
    {
        if (!getCanMove())
        {
            return false;
        }

        Point *location = Functions::PointMove(getCurrentLocation(), dir, 1);

        if (!getCurrentMap()->ValidPoint(location))
        {
            return false;
        }

        Cell *cell = getCurrentMap()->GetCell(location);

        if (!cell->Objects.empty())
        {
            for (int i = 0; i < cell->Objects.size(); i++)
            {
                MapObject *ob = cell->Objects[i];
                if (AvoidFireWall && ob->getRace() == ObjectType::Spell)
                {
                    if ((static_cast<SpellObject*>(ob))->Spell == Spell::FireWall)
                    {
                        return false;
                    }
                }

                if (!ob->getBlocking())
                {
                    continue;
                }

                return false;
            }
        }

        getCurrentMap()->GetCell(getCurrentLocation())->Remove(this);

        setDirection(dir);
        RemoveObjects(dir, 1);
        setCurrentLocation(location);
        getCurrentMap()->GetCell(getCurrentLocation())->Add(this);
        AddObjects(dir, 1);

        if (getHidden())
        {
            RemoveBuff(BuffType::Hiding);
        }

        CellTime = getEnvir()->getTime() + 500;
        ActionTime = getEnvir()->getTime() + 300;
        MoveTime = getEnvir()->getTime() + MoveSpeed;

        InSafeZone = getCurrentMap()->GetSafeZone(getCurrentLocation()) != nullptr;

        S::ObjectWalk *tempVar = new S::ObjectWalk();
        tempVar->ObjectID = ObjectID;
        tempVar->Direction = getDirection();
        tempVar->Location = getCurrentLocation();
        Broadcast(tempVar);

        cell = getCurrentMap()->GetCell(getCurrentLocation());

        for (int i = 0; i < cell->Objects.size(); i++)
        {
            if (cell->Objects[i]->getRace() != ObjectType::Spell)
            {
                continue;
            }
            SpellObject *ob = static_cast<SpellObject*>(cell->Objects[i]);

            ob->ProcessSpell(this);
            //break;
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
        return true;
    }

    Packet *ZumaMonster::GetInfo()
    {
        S::ObjectMonster *tempVar = new S::ObjectMonster();
        tempVar->ObjectID = ObjectID;
        tempVar->Name = getName();
        tempVar->NameColour = NameColour;
        tempVar->Location = getCurrentLocation();
        tempVar->Image = Info->Image;
        tempVar->Direction = getDirection();
        tempVar->Effect = Info->Effect;
        tempVar->AI = Info->AI;
        tempVar->Light = Info->Light;
        tempVar->Dead = Dead;
        tempVar->Skeleton = Harvested;
        tempVar->Poison = CurrentPoison;
        tempVar->Hidden = getHidden();
        tempVar->Extra = Stoned;

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was used in a 'return' or 'throw' statement.
        return tempVar;
    }
}
